#include "StdAfx.h"
#include "PortRouterMessage.h"
#include "DynamicBindingManager.h"
#include "PortRouter.h"
#include "ProtocolFactory.h"

#include "SimpleLogger.h"		// DEBUG -- hansohn, 18 May 2009

BOOST_CLASS_TRACKING(RoomFW::IPayload, ::boost::serialization::track_never);

namespace RoomFW {

const char* toString(PortRouterMessage::RouterMessageId rmid)
{
#define ENUM_TO_STRING_CASE(ENUM) case ENUM: return #ENUM;  break  // no trailing semicolon necessary
	switch(rmid)
	{
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_CONNECT);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_REGISTER);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_UNREGISTER);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_BIND);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_UNBIND);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_SEND);
		ENUM_TO_STRING_CASE(PortRouterMessage::RMID_NO_REPLY);
	}
	return "Unknown RouterMessageId";
}

PortRouterMessage::Ptr PortRouterMessage::Create(const std::string& msgStr)
{
	PortRouterMessage::Ptr retVal;

	std::istringstream iss(msgStr);
	iarchive iar(iss);

	int msgId;
	iar >> msgId;

	switch (msgId)
	{
	case RMID_CONNECT:
		retVal.reset(new PRM_Connect());
		break;
	case RMID_REGISTER:
		retVal.reset(new PRM_Register());
		break;
	case RMID_UNREGISTER:
		retVal.reset(new PRM_Unregister());
		break;
	case RMID_BIND:
		retVal.reset(new PRM_Bind());
		break;
	case RMID_BIND_ACK:
		retVal.reset(new PRM_Bind_Ack());
		break;
	case RMID_UNBIND:
		retVal.reset(new PRM_Unbind());
		break;
	case RMID_SEND:
		retVal.reset(new PRM_Send());
		break;
	default:
		ASSERT(false, "Invalid PortRouterMessage Id");
	}
	if (retVal)
	{
		iar >> *retVal;
	}
	return retVal;
}

PortRouterMessage::RouterMessageId PRM_Connect::getId() const
{
	return RMID_CONNECT;
}

void PRM_Connect::serialize(oarchive& ar, const unsigned int /*version*/) const
{
	G_LOG_2_SOFTWARE("PRM_Connect::serialize(oarchive), port_:%d, address_:%s", port_, address_.c_str());
	ar << port_ << address_;
}

void PRM_Connect::serialize(iarchive& ar, const unsigned int /*version*/)
{
	ar >> port_ >> address_;
G_LOG_2_SOFTWARE("PRM_Connect::serialize(iarchive), port_:%d, address_:%s", port_, address_.c_str());
}

void PRM_Connect::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_Connect::PRM_Connect()
	:
	port_(0),
	address_()
{
}

PRM_Connect::PRM_Connect(
	int port,
	std::string address)
	:
	port_(port),
	address_(address)
{
}

int PRM_Connect::port()
{
	return port_;
}

std::string PRM_Connect::address()
{
	return address_;
}


PortRouterMessage::RouterMessageId PRM_Register::getId() const
{
	return RMID_REGISTER;
}

void PRM_Register::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_1_SOFTWARE("PRM_Register::serialize(oarchive...), portName_:%s", portName_.c_str());
	ar << portName_ << typeId_ << isConjugate_;
}

void PRM_Register::serialize(iarchive& ar, const unsigned int /*version*/)
{
	ar >> portName_ >> typeId_ >> isConjugate_;
G_LOG_1_SOFTWARE("PRM_Register::serialize(iarchive...), portName_:%s", portName_.c_str());
}

void PRM_Register::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_Register::PRM_Register() :
	portName_(),
	typeId_(0),
	isConjugate_(false)
{
}

PRM_Register::PRM_Register(const std::string& portName, ContractTypeId typeId, bool isConjugate) :
	portName_(portName),
	typeId_(typeId),
	isConjugate_(isConjugate)
{
}

std::string PRM_Register::portName() const
{
	return portName_;
}

ContractTypeId PRM_Register::typeId() const
{
	return typeId_;
}

bool PRM_Register::isConjugate() const
{
	return isConjugate_;
}

PortRouterMessage::RouterMessageId PRM_Unregister::getId() const
{
	return RMID_UNREGISTER;
}

void PRM_Unregister::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_0_SOFTWARE("PRM_Unregister::serialize(oarchive");
}

void PRM_Unregister::serialize(iarchive& ar, const unsigned int /*version*/)
{
G_LOG_0_SOFTWARE("PRM_Unregister::serialize(iarchive");
}

void PRM_Unregister::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PortRouterMessage::RouterMessageId PRM_Bind::getId() const
{
	return RMID_BIND;
}

void PRM_Bind::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_3_SOFTWARE("PRM_Bind::serialize(oarchive), portName_:%s, portIndex_:(%d,%d)", portName_.c_str(), portIndex_.port(), portIndex_.replication());
	ar << portName_ << portIndex_;
}

void PRM_Bind::serialize(iarchive& ar, const unsigned int /*version*/)
{
	ar >> portName_ >> portIndex_;

G_LOG_3_SOFTWARE("PRM_Bind::serialize(iarchive), portName_:%s, portIndex_:(%d,%d)", portName_.c_str(), portIndex_.port(), portIndex_.replication());
}

void PRM_Bind::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_Bind::PRM_Bind() :
	portName_(),
	portIndex_()
{
}

PRM_Bind::PRM_Bind(const std::string& portName, PortIndex portIndex) :
	portName_(portName),
	portIndex_(portIndex)
{
}

std::string PRM_Bind::portName() const
{
	return portName_;
}

PortIndex PRM_Bind::portIndex() const
{
	return portIndex_;
}

PortRouterMessage::RouterMessageId PRM_Bind_Ack::getId() const
{
	return RMID_BIND_ACK;
}

void PRM_Bind_Ack::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_2_SOFTWARE("PRM_Bind_Ack::serialize(oarchive), portIndex_:(%d,%d)", portIndex_.port(), portIndex_.replication());
	ar << portIndex_;
}

void PRM_Bind_Ack::serialize(iarchive& ar, const unsigned int /*version*/)
{
	ar >> portIndex_;

G_LOG_2_SOFTWARE("PRM_Bind_Ack::serialize(iarchive), portIndex_:(%d,%d)", portIndex_.port(), portIndex_.replication());
}

void PRM_Bind_Ack::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_Bind_Ack::PRM_Bind_Ack() :
	portIndex_()
{
}

PRM_Bind_Ack::PRM_Bind_Ack(PortIndex portIndex) :
	portIndex_(portIndex)
{
}

PortIndex PRM_Bind_Ack::portIndex() const
{
	return portIndex_;
}

PortRouterMessage::RouterMessageId PRM_Unbind::getId() const
{
	return RMID_UNBIND;
}

void PRM_Unbind::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_0_SOFTWARE("PRM_Unbind::serialize(oarchive");
}

void PRM_Unbind::serialize(iarchive& ar, const unsigned int /*version*/)
{
G_LOG_0_SOFTWARE("PRM_Unbind::serialize(iarchive");
}

void PRM_Unbind::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PortRouterMessage::RouterMessageId PRM_Send::getId() const
{
	return RMID_SEND;
}

void PRM_Send::serialize(oarchive& ar, const unsigned int /*version*/) const
{
	G_LOG_5_SOFTWARE("PRM_Send::serialize(oarchive), senderName_:%s, replyId_:%d, portIndex_:(%d,%d), messageId_:%d",
				  senderName_.c_str(), replyId_, portIndex_.port(), portIndex_.replication(), messageId_);

	ar	<< contractId_
		<< senderName_
		<< replyId_
		<< portIndex_
		<< messageId_;
	if (payload_)
	{
		ar << *payload_;
	}
}

void PRM_Send::serialize(iarchive& ar, const unsigned int /*version*/)
{
	size_t payloadType;
	ar	>> contractId_
		>> senderName_
		>> replyId_
		>> portIndex_
		>> messageId_;
	ASSERT(ProtocolFactory::Get(contractId_));
	payload_ = ProtocolFactory::Get(contractId_)->createPayload(messageId_);
	if (payload_)
	{
		ar >> *payload_;
	}

	G_LOG_5_SOFTWARE("PRM_Send::serialize(iarchive), senderName_:%s, replyId_:%d, portIndex_:(%d,%d), messageId_:%d",
				  senderName_.c_str(), replyId_, portIndex_.port(), portIndex_.replication(), messageId_);
}

void PRM_Send::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_Send::PRM_Send() :
	contractId_(0),
	portIndex_(),
	messageId_(0),
	payload_(),
	senderName_(),
	replyId_(0)
{
}

PRM_Send::PRM_Send(
	ContractTypeId contractId,
	PortIndex portIndex,
	MessageID messageId,
	IPayloadSP payload,
	std::string senderName,
	int replyId)
	:
	contractId_(contractId),
	portIndex_(portIndex),
	messageId_(messageId),
	payload_(payload),
	senderName_(senderName),
	replyId_(replyId)
{
}

ContractTypeId PRM_Send::contractId() const
{
	return contractId_;
}

PortIndex PRM_Send::portIndex() const
{
	return portIndex_;
}

MessageID PRM_Send::messageId() const
{
	return messageId_;
}

IPayloadSP PRM_Send::payload() const
{
	return payload_;
}

IPayloadSP PRM_Send::releasePayload()
{
	IPayloadSP retVal = payload_;
	payload_.reset();
	return retVal;
}

std::string PRM_Send::senderName()
{
	return senderName_;
}

int PRM_Send::replyId() const
{
	return replyId_;
}

PortRouterMessage::RouterMessageId PRM_NoReply::getId() const
{
	return RMID_NO_REPLY;
}

void PRM_NoReply::serialize(oarchive& ar, const unsigned int /*version*/) const
{
G_LOG_0_SOFTWARE("PRM_NoReply::serialize(oarchive");
	ar	<< replyId_;
}

void PRM_NoReply::serialize(iarchive& ar, const unsigned int /*version*/)
{
G_LOG_0_SOFTWARE("PRM_NoReply::serialize(iarchive");
	ar	>> replyId_;
}

void PRM_NoReply::dispatch(PortRouter* router)
{
	router->dispatch(this);
}

PRM_NoReply::PRM_NoReply() :
	replyId_()
{
}

PRM_NoReply::PRM_NoReply(int replyId) :
	replyId_(replyId)
{
}

int PRM_NoReply::replyId() const
{
	return replyId_;
}


}
